package com.web.startup;

import com.web.datasource.DynamicDataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@ComponentScan(value = {"com.service", "com.dao"})
@PropertySources(value = {@PropertySource("classpath:database.properties")})
public class HibernateConfig {

    @Autowired
    private Environment env;

    @Value("${master.jdbc.driverClassName}")
    private String masterDriverClassName;
    @Value("${master.jdbc.url}")
    private String masterUrl;
    @Value("${master.jdbc.username}")
    private String masterUsername;
    @Value("${master.jdbc.password}")
    private String masterPassword;

    @Value("${slave.jdbc.driverClassName}")
    private String slaveDriverClassName;
    @Value("${slave.jdbc.url}")
    private String slaveUrl;
    @Value("${slave.jdbc.username}")
    private String slaveUsername;
    @Value("${slave.jdbc.password}")
    private String slavePassword;

    @Value("${hibernate.format_sql}")
    private String formatSql;
    @Value("${hibernate.show_sql}")
    private String showSql;
    @Value("${hibernate.hbm2ddl.auto}")
    private String hbm2ddlAuto;


    /**
     * 由env获取改为使用@Value属性注入，@PropertySources注解已不需要
     * 默认值：@Value("${key:defaultValue}")
     */
    @Bean
    @Profile("development")
    public DataSource masterDatasource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(masterDriverClassName);
        dataSource.setUrl(masterUrl);
        dataSource.setUsername(masterUsername);
        dataSource.setPassword(masterPassword);
        dataSource.setMaxIdle(150);  //连接池中最大的空闲的连接数 默认为 8
        dataSource.setMaxActive(150); //连接池中可同时连接的最大的连接数 默认值为 8,0为无限制,尽量保持与MaxIdle值一致
        dataSource.setMinIdle(30);   //连接池中最小的空闲的连接数 默认为 0
        dataSource.setInitialSize(10);   //连接池启动时创建的初始化连接数量 默认为 0
        dataSource.setTestOnBorrow(true);   //调用时检查是否为有效连接,当连接以秒为单位执行是应该设置为fasle,否则线程会阻塞严重,当为true时会降低性能
        dataSource.setTestOnReturn(false);   //返回连接池时检查是否为有效连接,当为true时会降低性能
        dataSource.setTestWhileIdle(true);  //指明连接是否被空闲连接回收器(如果有)进行检验
        dataSource.setRemoveAbandoned(true);    //是否自动回收超时连接
        dataSource.setRemoveAbandonedTimeout(180); //回收超时连接的超时时间
        dataSource.setMaxWait(3000);        //获取连接时最大等待时间,以毫秒为单位
        dataSource.setLogAbandoned(true);   //连接被泄露时是否打印
        dataSource.setValidationQuery("select 1"); //检验查询sql
        dataSource.setValidationQueryTimeout(5); //检验查询超时时间
        dataSource.setTimeBetweenEvictionRunsMillis(50000); //每隔50秒执行evictor线程,回收空闲连接，
        dataSource.setNumTestsPerEvictionRun(30); //evictor线程每次执行数量
        dataSource.setMinEvictableIdleTimeMillis(30); //evictor线程最小执行数量
        dataSource.setConnectionProperties("connectTimeout=120000;socketTimeout=120000"); //设置连接超时时间
        dataSource.setPoolPreparedStatements(false); //是否缓存preparedStatement,也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下关闭。
        dataSource.setMaxOpenPreparedStatements(-1); //要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true
        return dataSource;
    }

    @Bean
    @Profile("development")
    public DataSource slaveDatasource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(slaveDriverClassName);
        dataSource.setUrl(slaveUrl);
        dataSource.setUsername(slaveUsername);
        dataSource.setPassword(slavePassword);
        dataSource.setMaxIdle(150);  //连接池中最大的空闲的连接数 默认为 8
        dataSource.setMaxActive(150); //连接池中可同时连接的最大的连接数 默认值为 8,0为无限制,尽量保持与MaxIdle值一致
        dataSource.setMinIdle(30);   //连接池中最小的空闲的连接数 默认为 0
        dataSource.setInitialSize(10);   //连接池启动时创建的初始化连接数量 默认为 0
        dataSource.setTestOnBorrow(true);   //调用时检查是否为有效连接,当连接以秒为单位执行是应该设置为fasle,否则线程会阻塞严重,当为true时会降低性能
        dataSource.setTestOnReturn(false);   //返回连接池时检查是否为有效连接,当为true时会降低性能
        dataSource.setTestWhileIdle(true);  //指明连接是否被空闲连接回收器(如果有)进行检验
        dataSource.setRemoveAbandoned(true);    //是否自动回收超时连接
        dataSource.setRemoveAbandonedTimeout(180); //回收超时连接的超时时间
        dataSource.setMaxWait(3000);        //获取连接时最大等待时间,以毫秒为单位
        dataSource.setLogAbandoned(true);   //连接被泄露时是否打印
        dataSource.setValidationQuery("select 1"); //检验查询sql
        dataSource.setValidationQueryTimeout(5); //检验查询超时时间
        dataSource.setTimeBetweenEvictionRunsMillis(50000); //每隔50秒执行evictor线程,回收空闲连接，
        dataSource.setNumTestsPerEvictionRun(30); //evictor线程每次执行数量
        dataSource.setMinEvictableIdleTimeMillis(30); //evictor线程最小执行数量
        dataSource.setConnectionProperties("connectTimeout=120000;socketTimeout=120000"); //设置连接超时时间
        dataSource.setPoolPreparedStatements(false); //是否缓存preparedStatement,也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下关闭。
        dataSource.setMaxOpenPreparedStatements(-1); //要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true
        return dataSource;
    }

    /**
     * 默认配置为从库数据源，并添加主库数据源
     */
    @Bean
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(slaveDatasource());
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDatasource());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }


    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("com.core.model");
        Properties properties = new Properties();
        properties.put("hibernate.format_sql", formatSql);
        properties.put("hibernate.show_sql", showSql);
        properties.put("hibernate.hbm2ddl.auto", hbm2ddlAuto);
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
        properties.put("hibernate.cache.use_second_level_cache", "true");
        properties.put("hibernate.cache.use_query_cache", "true");
        properties.put("hibernate.cache.use_structured_entries", "true");
        properties.put("hibernate.current_session_context_class", "thread");
        properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
        properties.put("hibernate.cache.provider_configuration_file_resource_path", "ehcache.xml");
        sessionFactory.setHibernateProperties(properties);
        return sessionFactory;
    }


//    @Bean
//    public CacheManager cacheManager() {
////        CacheConfiguration cacheConfiguration = new CacheConfiguration("firstCache", 1);
//        net.sf.ehcache.config.Configuration configuration = new net.sf.ehcache.config.Configuration();
//        return new CacheHandle(configuration);
//    }


    @Bean
    public PlatformTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

}